/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package me.zhengjie.service.impl;

import me.zhengjie.domain.*;
import me.zhengjie.repository.*;
import me.zhengjie.service.mapstruct.FzAllSizeMapper;
import me.zhengjie.util.FileUtils;
import me.zhengjie.utils.*;
import lombok.RequiredArgsConstructor;
import me.zhengjie.service.FzSamplesService;
import me.zhengjie.service.dto.FzSamplesDto;
import me.zhengjie.service.dto.FzSamplesQueryCriteria;
import me.zhengjie.service.mapstruct.FzSamplesMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.util.IdUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

/**
 * @author zcc
 * @website https://el-admin.vip
 * @description 服务实现
 * @date 2021-07-03
 **/
@Service
@RequiredArgsConstructor
public class FzSamplesServiceImpl implements FzSamplesService {

    private final FzSamplesRepository fzSamplesRepository;
    private final FzSamplesMapper fzSamplesMapper;
    private final SampleTechnologyRepository sampleTechnologyRepository;
    private final FzFilesRepository fzFilesRepository;
    private final FzChunkRepository fzChunkRepository;

    private final FzAllSizeRepository fzAllSizeRepository;
    private final AllsizeTechnologyRepository allsizeTechnologyRepository;

    @Value("${file.windows.path}")
    private String uploadFolder;

    @Override
    public Map<String, Object> queryAll(FzSamplesQueryCriteria criteria, Pageable pageable) {
        Page<FzSamples> page = fzSamplesRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable);
        return PageUtil.toPage(page.map(fzSamplesMapper::toDto));
    }

    @Override
    public List<FzSamplesDto> queryAll(FzSamplesQueryCriteria criteria) {
        return fzSamplesMapper.toDto(fzSamplesRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    @Transactional
    public FzSamplesDto findById(String sampleId) {
        FzSamples fzSamples = fzSamplesRepository.findById(sampleId).orElseGet(FzSamples::new);
        ValidationUtil.isNull(fzSamples.getSampleId(), "FzSamples", "sampleId", sampleId);
        return fzSamplesMapper.toDto(fzSamples);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FzSamplesDto create(FzSamples resources) {
//        resources.setSampleId(IdUtil.simpleUUID());
        return fzSamplesMapper.toDto(fzSamplesRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(FzSamples resources) {
        FzSamples fzSamples = fzSamplesRepository.findById(resources.getSampleId()).orElseGet(FzSamples::new);
        ValidationUtil.isNull(fzSamples.getSampleId(), "FzSamples", "id", resources.getSampleId());
        fzSamples.copy(resources);
        fzSamplesRepository.save(fzSamples);
    }

    @Override
    public void deleteAll(String[] ids) {
        for (String sampleId : ids) {
            fzSamplesRepository.deleteById(sampleId);
            List<SampleTechnology> list = sampleTechnologyRepository.findBySampleId(sampleId);
            sampleTechnologyRepository.deleteAll(list);

            List<ErpFiles> files = fzFilesRepository.findBybid(sampleId);
            fzFilesRepository.deleteAll(files);

            List<ErpChunk> chunks = fzChunkRepository.findBybid(sampleId);
            fzChunkRepository.deleteAll(chunks);

            String sourcePath = uploadFolder + SecurityUtils.getCurrentUsername() + File.separator + sampleId;
            FileUtils.deleteDir(new File(sourcePath));
        }
    }

    @Override
    public void download(List<FzSamplesDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (FzSamplesDto fzSamples : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("文件名称", fzSamples.getFileName());
            map.put("日期", fzSamples.getDateTime());
            map.put("客户", fzSamples.getCustomer());
            map.put("类别", fzSamples.getTypes());
            map.put("菲林", fzSamples.getFeilin());
            map.put("模具", fzSamples.getModel());
            map.put("备注", fzSamples.getRemark());
            map.put("针数", fzSamples.getNeedleNum());
            map.put("行数", fzSamples.getSampleRows());
            map.put("单片时间", fzSamples.getSingleChipTime());
            map.put("单片重量", fzSamples.getWeight());
            map.put("烫机温度", fzSamples.getScaldTemp());
            map.put("烫机速度", fzSamples.getScaldSpeed());
            map.put("烫机压力", fzSamples.getScaldPre());
            map.put("样品工艺", fzSamples.getSampleTechnologyId());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean copyTo(String bid, String type) throws IOException {
        FzSamples samples = fzSamplesRepository.findById(bid).orElseGet(FzSamples::new);
        String newSid = IdUtil.simpleUUID();
        List<SampleTechnology> technologies = sampleTechnologyRepository.findBySampleId(bid);
        if ("sample".equals(type)) {
            List<SampleTechnology> newTechs = new ArrayList<>();
            for (SampleTechnology technology : technologies) {
                SampleTechnology newsame = new SampleTechnology();
                technology.copyTo(newsame);
                newsame.setTechId(IdUtil.simpleUUID());
                newsame.setSampleId(newSid);

                newTechs.add(newsame);
            }
            sampleTechnologyRepository.saveAll(newTechs);

            FzSamples newSamples = new FzSamples();
            samples.copyTo(newSamples);
            newSamples.setSampleId(newSid);
            newSamples.setSampleTechnologyId(newTechs.stream().map(SampleTechnology::getTechId).collect(Collectors.joining(",")));
            fzSamplesRepository.save(newSamples);
        }else if ("allSize".equals(type)) {
            List<AllsizeTechnology> newTechs = new ArrayList<>();
            for (SampleTechnology technology : technologies) {
                AllsizeTechnology newsize = new AllsizeTechnology();
                technology.copyToAllsize(newsize);
                newsize.setTechId(IdUtil.simpleUUID());
                newsize.setAsId(newSid);

                newTechs.add(newsize);
            }
            allsizeTechnologyRepository.saveAll(newTechs);

            FzAllSize allSize = new FzAllSize();
            samples.copyToAllSize(allSize);
            allSize.setAsId(newSid);
            allSize.setAllsizeTechnologyId(newTechs.stream().map(AllsizeTechnology::getTechId).collect(Collectors.joining(",")));
            fzAllSizeRepository.save(allSize);
        }

        copyAttach(newSid, bid, type);

        return true;
    }

    public void copyAttach(String newSid, String bid, String type) throws IOException {
        List<ErpFiles> files = fzFilesRepository.findBybid(bid);
        List<ErpFiles> newfiles = new ArrayList<>();
        for (ErpFiles file : files) {
            ErpFiles newFile = new ErpFiles();
            file.copyTo(newFile);
            newFile.setId(IdUtil.simpleUUID());
            newFile.setBId(newSid);
            newFile.setFType(type);

            newfiles.add(newFile);
        }
        fzFilesRepository.saveAll(newfiles);

        List<ErpChunk> chunks = fzChunkRepository.findBybid(bid);
        List<ErpChunk> newchunks = new ArrayList<>();
        for (ErpChunk chunk : chunks) {
            ErpChunk newchunk = new ErpChunk();
            chunk.copyTo(newchunk);
            newchunk.setBId(newSid);
            newchunk.setId(IdUtil.simpleUUID());
            newchunk.setFType(type);

            newchunks.add(newchunk);
        }
        fzChunkRepository.saveAll(newchunks);

        String sourcePath = uploadFolder + SecurityUtils.getCurrentUsername() + File.separator + bid;
        String targetPath = uploadFolder + SecurityUtils.getCurrentUsername() + File.separator + newSid;
        dirCopy(sourcePath, targetPath);
    }

    //复制函数
    static void dirCopy(String srcAbspath, String destAbspath) throws IOException {
        File src = new File(srcAbspath);
        File dest = new File(destAbspath);

        if (!dest.exists()){
            dest.mkdirs();
        }

        //1.检查路径是否可达
        //（代码过多就省略展示了）
        //2.判断所在文件夹是否相同
        if (!src.getPath().equals(dest.getPath())) {

            //3.判断是否是文件夹或者是文件
            if (src.isFile()) {
                dest = new File(dest.getPath() + File.separator + src.getName());
                copyFile(src, dest);//复制文件的部分，代码在下面
                return;
            } else {
                //4.递归调用
                for (File file : src.listFiles()) {
                    function1(file, dest);
                }
            }
        }  //（代码过多就省略展示了,这一部分是复制的路径和源文件的路径相同的情况下）

    }

    //建立递归函数
    private static void function1(File file1, File file2) throws IOException {
        if (file1 == null || !file1.exists()) {
            return;                                    //递归头
        } else {                                        //递归体
            if (file1.isFile()) {
                //如果是直接修改file2的话，会影响下一次的循环中的file2，所以我建立新的file3
                File file3 = new File(file2.getPath() + File.separator + file1.getName());
                //这一步必须执行，否者找不到文件
                file3.createNewFile();
                copyFile(file1, file3);                //复制代码
            } else {
                //每次根深层次的复制的时候，必须提前将两个file对象的进行同步
                file2 = new File(file2.getPath() + File.separator + file1.getName());
                file2.mkdirs();
                for (File file : file1.listFiles()) {
                    function1(file, file2);
                }
            }
        }
    }

    //复制文件
    static void copyFile(File file1, File file2) {
        OutputStream os = null;
        InputStream is = null;
        try {
            os = new FileOutputStream(file2);
            is = new FileInputStream(file1);
            byte[] b = new byte[1024 * 4];
            int item = -1;
            while ((item = is.read(b)) != -1) {
                os.write(b, 0, item);
            }
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}